package com.zFace.LRU;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 类说明：利用 LinkedHashMap 实现简单的缓存， 必须实现 removeEldestEntry 方法，具体参见JDK文档
 *
 * @param <K>
 * @param <V>
 */
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {

	/**
	 * 容量
	 */
	private final int maxCapacity;

	/**
	 * 负载因子
	 */
	private static final float DEFAULT_LOAD_FACTOR = 0.75f;

	private final Lock lock = new ReentrantLock();

	public LRULinkedHashMap(int maxCapacity) {
		// accessOrder → false：基于插入顺序  true：基于访问顺序
		/**
		 * public static void main(String[] args) {
		 *         Map<String, String> map = new LinkedHashMap<String, String>(16,0.75f,true);
		 *         map.put("1", "a");
		 *         map.put("2", "b");
		 *         map.put("3", "c");
		 *         map.put("4", "e");
		 *
		 *         //new add
		 *         map.get("1");
		 *         map.get("2");
		 *
		 *         for (Iterator<String> iterator = map.values().iterator(); iterator
		 *                 .hasNext();) {
		 *             String name = (String) iterator.next();
		 *             System.out.print(name);
		 *         }
		 *     }
		 * 打印结果 'ceab'
		 * 这就是基于访问的顺序，get一个元素后，这个元素被加到最后(使用了LRU 最近最少被使用的调度算法)
		 */
		super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
		this.maxCapacity = maxCapacity;
	}

	/**
	 * 重写此方法来判断是否移除元素
	 *
	 * @param eldest
	 * @return
	 */
	@Override
	protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
		return size() > maxCapacity;
	}

	@Override
	public boolean containsKey(Object key) {
		lock.lock();
		try {
			return super.containsKey(key);
		} finally {
			lock.unlock();
		}
	}


	@Override
	public V get(Object key) {
		lock.lock();
		try {
			return super.get(key);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public V put(K key, V value) {
		lock.lock();
		try {
			return super.put(key, value);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public int size() {
		lock.lock();
		try {
			return super.size();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void clear() {
		lock.lock();
		try {
			super.clear();
		} finally {
			lock.unlock();
		}
	}

	public Collection<Map.Entry<K, V>> getAll() {
		lock.lock();
		try {
			return new ArrayList<Map.Entry<K, V>>(super.entrySet());
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		Map map = new LRULinkedHashMap(3);
		map.put(1, "a");
		System.out.println(map);
		map.put(2, "b");
		System.out.println(map);
		map.put(3, "c");
		System.out.println(map);
		map.put(4, "d");
		System.out.println(map);
		map.put(1, "a");
		System.out.println(map);
		map.put(2, "b");
		System.out.println(map);
	}
}
